﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Dynamic;
using System.Linq;
using System.Text;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.Rebar;

namespace FreeRobot.Common
{
    internal unsafe class MapEx
    {
        private readonly int _row, _col;
        private readonly MazeGenerator _mazeGenerator;
        public MapEx(int row, int column)
        {
            _row = row;
            _col = column;
            _mazeGenerator=new MazeGenerator(_row, _col);
        }
        public CellInfo GetMap(int index)
        {
            if (index == 0)
                return Map1();
            else
                return _mazeGenerator.GenerateMaze();
        }
        public CellInfo Map1()
        {
            sbyte[,] map = new sbyte[_row, _col];

            CellInfo cellInfo = new CellInfo();
            cellInfo.Map = map;
            cellInfo.Start = new Point(0, 0);
            cellInfo.End = new Point(_row-1, _col-1);
            map[cellInfo.End.X, cellInfo.End.Y] = 2;
            return cellInfo;
        }
    }
    public class CellInfo
    {
        public Point Start { get; set; }
        public Point End { get; set; }
        public sbyte[,] Map { get; set; }
    }
    public unsafe class MazeGenerator
    {
        private sbyte[,] map;
        private int _row;
        private int _col;
        private int startRow;
        private int startCol;
        private int exitRow;
        private int exitCol;

        public MazeGenerator(int row, int col)
        {
            _row = row;
            _col = col;
            map = new sbyte[_row, _col];
        }

        public CellInfo GenerateMaze()
        {
            InitializeMap();
            Random rand = new Random();
            startRow = rand.Next(1, _row>>1) | 1;
            startCol = rand.Next(1, _col >>1) | 1;
            Generate(startRow, startCol);
            FindExit();
            return new CellInfo
            {
                Start = new Point(startCol, startRow),
                End = new Point(exitCol, exitRow),
                Map = map
            };
        }

        private void InitializeMap()
        {
            fixed (sbyte* ptr = map)
            {
                for (int i = 0; i < _row; i++)
                {
                    for (int j = 0; j < _col; j++)
                    {
                        sbyte* cur = ptr + i * _col + j;
                        *cur = 1;
                    }
                }
            }
        }

        private int[] dx = { -2, 2, 0, 0 }; 
        private int[] dy = { 0, 0, -2, 2 };

        private void Generate(int row, int col)
        {
            map[row, col] = 0; 

            int[] randomDirectionIndices = { 0, 1, 2, 3 };
            Random rand = new Random();
            for (int i = 0; i < randomDirectionIndices.Length; i++)
            {
                int randomIndex = rand.Next(i, randomDirectionIndices.Length);
                int temp = randomDirectionIndices[i];
                randomDirectionIndices[i] = randomDirectionIndices[randomIndex];
                randomDirectionIndices[randomIndex] = temp;
            }

            foreach (var i in randomDirectionIndices)
            {
                int nextRow = row + dx[i];
                int nextCol = col + dy[i];

                if (IsValid(nextRow, nextCol)) // Check bounds
                {
                    int betweenRow = (row + nextRow) / 2;
                    int betweenCol = (col + nextCol) / 2;

                    if (map[nextRow, nextCol] == 1) // Only proceed if the cell has not been visited
                    {
                        map[betweenRow, betweenCol] = 0; // Open path between cells
                        Generate(nextRow, nextCol);
                    }
                }
            }
        }

        private bool IsValid(int row, int col)
        {
            if (row < 0 || col < 0 || row >= _row || col >= _col)
                return false;
            return true;
        }

        private void FindExit()
        {
            exitRow = _row - 2;
            exitCol = _col - 2;
            map[exitRow, exitCol] = 0;
        }

        public void PrintMaze()
        {
            for (int i = 0; i < _row; i++)
            {
                for (int j = 0; j < _col; j++)
                {
                    Console.Write(map[i, j] == 0 ? " " : "#");
                }
                Console.WriteLine();
            }
        }
    }
}
